package cn.yhbk.web.modules.manager.Service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.yhbk.web.common.api.CommonPage;
import cn.yhbk.web.common.api.CommonResult;
import cn.yhbk.web.common.exception.ApiException;
import cn.yhbk.web.modules.manager.Pojo.DTO.Gpa.GpaDto;
import cn.yhbk.web.modules.manager.Pojo.DTO.Gpa.GpaPagResp;
import cn.yhbk.web.modules.manager.Pojo.Entity.TbClass;
import cn.yhbk.web.modules.manager.Pojo.Entity.TbGpaRecord;
import cn.yhbk.web.modules.manager.Mapper.TbGpaRecordMapper;
import cn.yhbk.web.modules.manager.Pojo.Entity.TbMajor;
import cn.yhbk.web.modules.manager.Pojo.Entity.TbStudent;
import cn.yhbk.web.modules.manager.Pojo.VO.Apply.ApplyResp;
import cn.yhbk.web.modules.manager.Pojo.VO.GpaRecord.GpaRecordAdd;
import cn.yhbk.web.modules.manager.Pojo.VO.GpaRecord.GpaRecordGet;
import cn.yhbk.web.modules.manager.Pojo.VO.GpaRecord.GpaRecordResP;
import cn.yhbk.web.modules.manager.Pojo.VO.OrderResponse;
import cn.yhbk.web.modules.manager.Service.ITbGpaRecordService;
import cn.yhbk.web.modules.manager.Service.ITbScholarshipService;
import cn.yhbk.web.modules.manager.Service.ITbStudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 绩点记录表 服务实现类
 * </p>
 *
 * @author 有何不可
 * @since 2023-08-05
 */
@Service
@Slf4j
public class TbGpaRecordServiceImpl extends ServiceImpl<TbGpaRecordMapper, TbGpaRecord> implements ITbGpaRecordService {


    @Autowired
    ITbStudentService studentService;

    @Autowired
    private TbClassServiceImpl classService;

    @Autowired
    private ITbScholarshipService tbScholarshipService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean addRecord(GpaRecordAdd add) {
        //log.debug("绩点记录：{}",add);
        //校验当前年份该学生是否已经有一份绩点记录
        int currentYear = LocalDate.now().getYear();
        String year = String.valueOf(currentYear);
        QueryWrapper<TbGpaRecord> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<TbGpaRecord> lambda = wrapper.lambda();

        lambda.eq(TbGpaRecord::getStuId,add.getStuId());
        lambda.eq(TbGpaRecord::getYear,year);

        List<TbGpaRecord> list = list(lambda);
        if(!list.isEmpty()){
            log.error("重复添加绩点");
            throw new ApiException("当前年份该学生已经存在一份绩点记录,请勿重复添加!");
        }



        TbGpaRecord gpaRecord = new TbGpaRecord();
        BeanUtil.copyProperties(add,gpaRecord);

        //设置当前年份
        gpaRecord.setYear(year);
        //计算各绩点
        calculate(gpaRecord);
        //log.debug("绩点记录：{}",gpaRecord);

        return save(gpaRecord);
    }

    @Override
    public CommonPage<GpaRecordResP> getRecord(Long currentPage, Long pageSize, GpaRecordGet condition) {
        Page<TbGpaRecord> page = new Page<>(currentPage, pageSize);

        QueryWrapper<TbGpaRecord> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<TbGpaRecord> lambda = wrapper.lambda();

        Long id = condition.getId();
        if(!Objects.isNull(id))lambda.eq(TbGpaRecord::getId,id);

        Long standardId = condition.getStandardId();
        if(!Objects.isNull(standardId))lambda.eq(TbGpaRecord::getStandardId,standardId);

        String notes = condition.getNotes();
        if(!Strings.isBlank(notes))lambda.like(TbGpaRecord::getNotes,notes);

        Double cadreGpa = condition.getCadreGpa();
        if(!Objects.isNull(cadreGpa))lambda.eq(TbGpaRecord::getCadreGpa,cadreGpa);

        Double activityGpa = condition.getActivityGpa();
        if(!Objects.isNull(activityGpa))lambda.eq(TbGpaRecord::getActivityGpa,activityGpa);

        Double skillGpa = condition.getSkillGpa();
        if(!Objects.isNull(skillGpa))lambda.eq(TbGpaRecord::getSkillGpa,skillGpa);

        Double actGpa = condition.getActGpa();
        if(!Objects.isNull(actGpa))lambda.eq(TbGpaRecord::getActGpa,actGpa);

        Double scoreGpaLeft = condition.getScoreGpaLeft();
        Double scoreGpaRight = condition.getScoreGpaRight();
        if(!Objects.isNull(scoreGpaLeft) && !Objects.isNull(scoreGpaRight))lambda.between(TbGpaRecord::getScoreGpa,scoreGpaLeft,scoreGpaRight);

        String year = condition.getYear();
        if(!Strings.isBlank(year))lambda.eq(TbGpaRecord::getYear,year);

        Boolean pass = condition.getPass();
        if(!Objects.isNull(pass))lambda.eq(TbGpaRecord::getPass,pass);

        Long stuId = condition.getStuId();
        if(!Objects.isNull(stuId))lambda.eq(TbGpaRecord::getStuId,stuId);

        Double gpaSumLeft = condition.getGpaSumLeft();
        Double gpaSumRight = condition.getGpaSumRight();
        if(!Objects.isNull(gpaSumLeft) && !Objects.isNull(gpaSumRight))lambda.between(TbGpaRecord::getGpaSum,gpaSumLeft,gpaSumRight);

        Double gpaQualityLeft = condition.getGpaQualityLeft();
        Double gpaQualityRight = condition.getGpaQualityRight();
        if(!Objects.isNull(gpaQualityLeft) && !Objects.isNull(gpaQualityRight))lambda.between(TbGpaRecord::getGpaQuality,gpaQualityLeft,gpaQualityRight);

        Byte status = condition.getStatus();
        lambda.eq(!Objects.isNull(status),TbGpaRecord::getStatus,status);

        Page<TbGpaRecord> dataPage = page(page, lambda);
        CommonPage<GpaRecordResP> resPage = CommonPage.restPage(dataPage, new CommonPage<GpaRecordResP>());
        List<GpaRecordResP> dataList = packData(dataPage.getRecords());
        resPage.setList(dataList);

        return resPage;

    }

    @Override
    public TbGpaRecord getRecordByStudentId(Long studentId) {
        if(Objects.isNull(studentId))return new TbGpaRecord();
        QueryWrapper<TbGpaRecord> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<TbGpaRecord> lambda = wrapper.lambda();


        lambda.eq(TbGpaRecord::getStuId,studentId);
        String year = String.valueOf(LocalDate.now().getYear());
        lambda.eq(TbGpaRecord::getYear,year);
        List<TbGpaRecord> list = list(lambda);
        if(list.size() != 1){
            log.error("list:{}",list);
            log.error("stuId:{}",studentId);
            log.error("发生错误");
            throw new ApiException("绩点记录发生错误，请联系管理员");
        }
        return list.get(0);
    }

    @Override
    public boolean updateGpa(Long studentId, Double gpaSum, Double gpaQuality) {
        if(Objects.isNull(studentId) || Objects.isNull(gpaSum) || Objects.isNull(gpaQuality))return false;
        UpdateWrapper<TbGpaRecord> wrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<TbGpaRecord> lambda = wrapper.lambda();

        lambda.eq(TbGpaRecord::getStuId,studentId);
        String year = String.valueOf(LocalDate.now().getYear());
        lambda.eq(TbGpaRecord::getYear,year);

        lambda.set(TbGpaRecord::getGpaSum,gpaSum);
        lambda.set(TbGpaRecord::getGpaQuality,gpaQuality);
        return update(lambda);
    }

    private List<GpaRecordResP> packData(List<TbGpaRecord> records) {
        List<Long> stuIds = records.stream().map(TbGpaRecord::getStuId).collect(Collectors.toList());
        if(stuIds.isEmpty())stuIds.add(-1L);
        List<TbStudent> students = studentService.listByIds(stuIds);
        Map<Long, TbStudent> studentIdMap = students.stream().collect(Collectors.toMap(TbStudent::getId, item -> item));

        return records.stream().map(item->{
            GpaRecordResP resP = new GpaRecordResP();
            BeanUtil.copyProperties(item,resP);

            //设置学生对象
            resP.setStudent(studentIdMap.get(item.getStuId()));
            return resP;
        }).collect(Collectors.toList());
    }

    private void calculate(TbGpaRecord gpaRecord) {

        //计算素质加分
        double qualityGpa = gpaRecord.getCadreGpa()+gpaRecord.getActivityGpa()+gpaRecord.getSkillGpa()+gpaRecord.getActGpa();
        gpaRecord.setGpaQuality(qualityGpa);

        //计算总分
        double sum = qualityGpa+gpaRecord.getScoreGpa();
        gpaRecord.setGpaSum(sum);
    }

    @Override
    public List<GpaDto> getGpaRecordSort(Long stuId, Long scholarshipId) {
        // 判断是否满足申请条件
        String isBeginApply = String.valueOf(redisTemplate.opsForValue().get("isBeginApply"));
        if (isBeginApply == null || isBeginApply.equals("0")){
            throw new ApiException("未在规定的申请时间范围内");
        }

        // 获取当前年份
        LocalDate localDate = LocalDate.now();
        int year = localDate.getYear();

        // 查询用户的专业
        TbStudent student = studentService.getOne(new QueryWrapper<TbStudent>().select("class_id").eq("id", stuId));
        TbClass tbClass = classService.getOne(new QueryWrapper<TbClass>().select("major_id, grade_id").eq("id", student.getClassId()));
        String getStr = (String) redisTemplate.opsForValue().get("gpaSort:" + tbClass.getMajorId() + "-" + scholarshipId + "-" + tbClass.getGradeId());
        if (getStr != null && !getStr.isEmpty()){
            return JSONUtil.toList(getStr, GpaDto.class);
        }

        List<GpaDto> gpaRecordSort = this.baseMapper.getGpaRecordSort(year, tbClass.getMajorId(), tbClass.getGradeId());
        gpaRecordSort = tbScholarshipService.getScholarshipSort(gpaRecordSort, tbClass.getMajorId(), scholarshipId, tbClass.getGradeId());

        redisTemplate.opsForValue().set("gpaSort:" + tbClass.getMajorId() + "-" + scholarshipId + "-" + tbClass.getGradeId(), JSONUtil.toJsonStr(gpaRecordSort), 5, TimeUnit.HOURS);
        return gpaRecordSort;
    }

    @Override
    public GpaPagResp getGpaSort(Long adminId, Long gradeId, Long majorId, Integer currPage, Integer pageSize, Integer year) {
        GpaPagResp gpaPagResp = new GpaPagResp();
        gpaPagResp.setCurrPage(currPage);
        gpaPagResp.setPageSize(pageSize);
        // 默认当前年份
        if (year == null){
            LocalDate localDate = LocalDate.now();
            year = localDate.getYear();
        }
        gpaPagResp.setGpaDtoList(this.baseMapper.getGpaRecordSortByLimit(year, majorId, gradeId, (currPage - 1) * pageSize, pageSize));
        gpaPagResp.setTotal(this.baseMapper.getGpaRecordSortByLimitCount(year, majorId, gradeId, (currPage - 1) * pageSize, pageSize));

        return gpaPagResp;
    }

    @Override
    public List<OrderResponse> getRecordByStudentIds(List<Long> studentIds) {
        if(studentIds.isEmpty())return new ArrayList<>();
        LambdaQueryWrapper<TbGpaRecord> lambda = new QueryWrapper<TbGpaRecord>().lambda();

        lambda.in(TbGpaRecord::getStuId,studentIds);
        lambda.orderByDesc(TbGpaRecord::getGpaSum);
        List<TbGpaRecord> list = list(lambda);
        return packageToApplyResP(list);
    }

    private List<OrderResponse> packageToApplyResP(List<TbGpaRecord> list) {
        return list.stream().map(item->{
            OrderResponse response = new OrderResponse();
            Long stuId = item.getStuId();
            TbStudent student = studentService.getById(stuId);
            if(Objects.isNull(student))throw new ApiException("该学生不存在!");
            response.setStuId(stuId);
            response.setStuName(student.getName());
            response.setJobNumber(String.valueOf(student.getJobNumber()));

            response.setGpaSum(item.getGpaSum());

            Long classId = student.getClassId();
            TbClass tbClass = classService.getById(classId);
            if(Objects.isNull(tbClass))throw new ApiException("该班级不存在!");

            response.setClassDescription(tbClass.getDescription());

            response.setYear(item.getYear());
            return response;
        }).collect(Collectors.toList());

    }
}
